package pers.lys.aigc4chat.model.baidu.util;

import java.util.Date;
import java.util.Locale;
import java.util.regex.Pattern;

import lombok.experimental.UtilityClass;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;

/**
 * 日期工具类
 * <p>Utilities for parsing and formatting dates.
 * Note that this class doesn't use static methods because of the synchronization issues with SimpleDateFormat.
 * This lets synchronization be done on a per-object level, instead of on a per-class level.
 *
 * @author hll
 * @since 2024/05/06
 */
@UtilityClass
public class DateUtil {

    /**
     * ISO 8601 format
     */
    private final DateTimeFormatter ISO_8601_DATE_FORMAT =
            ISODateTimeFormat.dateTime().withZone(DateTimeZone.UTC);

    /**
     * Alternate ISO 8601 format without fractional seconds
     */
    private final DateTimeFormatter ALTERNATE_ISO_8601_DATE_FORMAT =
            ISODateTimeFormat.dateTimeNoMillis().withZone(DateTimeZone.UTC);

    /**
     * RFC 822 format
     */
    private final DateTimeFormatter RFC_822_DATE_FORMAT = DateTimeFormat
            .forPattern("EEE, dd MMM yyyy HH:mm:ss 'GMT'")
            .withLocale(Locale.US)
            .withZone(DateTimeZone.UTC);

    /**
     * This is another ISO 8601 format that's used in clock skew error response
     */
    private final DateTimeFormatter COMPRESSED_ISO_8601_DATE_FORMAT =
            ISODateTimeFormat.basicDateTimeNoMillis().withZone(DateTimeZone.UTC);

    /**
     * Parses the specified date string as an ISO 8601 date and returns the Date object.
     *
     * @param dateString The date string to parse.
     * @return The parsed Date object.
     */
    public Date parseIso8601Date(String dateString) {
        try {
            return DateUtil.ISO_8601_DATE_FORMAT.parseDateTime(dateString).toDate();
        } catch (IllegalArgumentException e) {
            // If the first ISO 8601 parser didn't work, try the alternate
            // version which doesn't include fractional seconds
            return DateUtil.ALTERNATE_ISO_8601_DATE_FORMAT.parseDateTime(dateString).toDate();
        }
    }

    /**
     * Formats the specified date as an ISO 8601 string.
     *
     * @param date The date to format.
     * @return The ISO 8601 string representing the specified date.
     */
    public String formatIso8601Date(Date date) {
        return DateUtil.ISO_8601_DATE_FORMAT.print(new DateTime(date));
    }

    /**
     * Parses the specified date string as an ISO 8601 date and returns the Date object.
     *
     * @param dateString The date string to parse.
     * @return The parsed Date object.
     */
    public Date parseAlternateIso8601Date(String dateString) {
        return DateUtil.ALTERNATE_ISO_8601_DATE_FORMAT.parseDateTime(dateString).toDate();
    }

    /**
     * Formats the specified date as an ISO 8601 string.
     *
     * @param date The date to format.
     * @return The ISO 8601 string representing the specified date.
     */
    public String formatAlternateIso8601Date(Date date) {
        return DateUtil.ALTERNATE_ISO_8601_DATE_FORMAT.print(new DateTime(date));
    }

    /**
     * Parses the specified date string as an RFC 822 date and returns the Date object.
     *
     * @param dateString The date string to parse.
     * @return The parsed Date object.
     */
    public Date parseRfc822Date(String dateString) {
        return DateUtil.RFC_822_DATE_FORMAT.parseDateTime(dateString).toDate();
    }

    /**
     * Formats the specified date as an RFC 822 string.
     *
     * @param date The date to format.
     * @return The RFC 822 string representing the specified date.
     */
    public String formatRfc822Date(Date date) {
        return DateUtil.RFC_822_DATE_FORMAT.print(new DateTime(date));
    }

    /**
     * Parses the specified date string as a compressedIso8601DateFormat ("yyyyMMdd'T'HHmmss'Z'") and returns the Date
     * object.
     *
     * @param dateString The date string to parse.
     * @return The parsed Date object.
     */
    public Date parseCompressedIso8601Date(String dateString) {
        return DateUtil.COMPRESSED_ISO_8601_DATE_FORMAT.parseDateTime(dateString).toDate();
    }

    public void validateUtcDate(String dateString) {
        if (StringUtils.isBlank(dateString)) {
            return;
        }
        String pattern = "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z";
        if (!Pattern.matches(pattern, dateString)) {
            throw new IllegalArgumentException("UTC date format is illegal");
        }
    }
}